package com.zero.code;

import cn.hutool.json.JSONObject;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.*;
import java.util.Base64;

public class RSACode {
    private static String publicKey;
    private static String privateKey;
    private static String Algorithm = "RSA";
    private static String Sign_Algorithm = "SHA1WithRSA";
    private static String Format = "utf-8";

    public static void generatePairKey() throws NoSuchAlgorithmException {
        // RSA密钥对生成器
        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
        // 密钥长度，1024已被破解，建议2046
        generator.initialize(1024);
        // 生成一个密钥对
        KeyPair keyPair = generator.generateKeyPair();
        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
        /*JSONObject jsonObject = new JSONObject(rsaPublicKey);
        JSONObject jsonObject1 = new JSONObject(rsaPrivateKey);
        System.out.println(jsonObject);
        System.out.println(jsonObject1);*/
        //System.out.println("algorithm:"+publicKey.getAlgorithm()+"format"+publicKey.getFormat()+"encoded"+new String(publicKey.getEncoded()));
        publicKey = new String(Base64.getEncoder().encode(rsaPublicKey.getEncoded()));
        System.out.println("公钥：" + publicKey);
        privateKey = new String(Base64.getEncoder().encode(rsaPrivateKey.getEncoded()));
        System.out.println("私钥：" + privateKey);
    }

    public static String encode(String source, String publicKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        byte[] encode = Base64.getDecoder().decode(publicKeyStr);
        // 反向生成公钥
        RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(encode));
        // 获取一个加密器实例
        Cipher cipher = Cipher.getInstance(Algorithm);
        // 初始化
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        // 加密
        byte[] result = cipher.doFinal(source.getBytes());
        return new String(Base64.getEncoder().encode(result));
    }

    public static String decode(String source, String privateKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        byte[] encode = Base64.getDecoder().decode(privateKeyStr);
        RSAPrivateKey privateKey = (RSAPrivateKey) KeyFactory.getInstance(Algorithm).generatePrivate(new PKCS8EncodedKeySpec(encode));
        // 获取一个解密器实例
        Cipher cipher = Cipher.getInstance(Algorithm);
        // 初始化
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        // 解密
        byte[] result = cipher.doFinal(Base64.getDecoder().decode(source));
        return new String(result);
    }

    public static String sign(String source, String privateKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, SignatureException {
        byte[] encode = Base64.getDecoder().decode(privateKeyStr);
        RSAPrivateKey privateKey = (RSAPrivateKey) KeyFactory.getInstance(Algorithm).generatePrivate(new PKCS8EncodedKeySpec(encode));
        // 获取一个签名实例
        Signature signature = Signature.getInstance(Sign_Algorithm);
        // 初始化
        signature.initSign(privateKey);
        signature.update(Base64.getDecoder().decode(source));
        // 签名
        byte[] result = signature.sign();
        return new String(Base64.getEncoder().encode(result));
    }

    public static boolean validSign(String source, String signData, String publicKeyStr) throws NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, SignatureException {
        byte[] encode = Base64.getDecoder().decode(publicKeyStr);
        // 反向生成公钥
        RSAPublicKey publicKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(encode));
        // 获取一个验签名实例
        Signature signature = Signature.getInstance(Sign_Algorithm);
        // 初始化
        signature.initVerify(publicKey);
        signature.update(Base64.getDecoder().decode(source));
        return signature.verify(Base64.getDecoder().decode(signData));
    }


    public static void main(String[] args) throws Exception {
        String source = "abc";
        generatePairKey();
        // 加密后base64数据
        String rsaEncode = encode(source, publicKey);
        System.out.println("加密后base64数据"+rsaEncode);
        // 签名base64数据
        String signData = sign(source, privateKey);
        System.out.println("签名base64数据"+signData);
        String decodeSource = decode(rsaEncode, privateKey);
        System.out.println("解密后原文"+decodeSource);
        if(validSign(decodeSource, signData, publicKey)){
            System.out.println("验证签名成功");
        }else{
            System.out.println("验证签名失败");
        }
    }
}
